<template>
	<view style="overflow: hidden;">
		<view class="l-pull-refresh" ref="refreshRef" :style="[pullDownRefreshStyle]" @touchstart="onTouchStart"
			@touchmove="onTouchMove" @touchend="onTouchEnd">
			<view class="l-pull-refresh__header" ref="headerRef" :style="headerStyle">
				<slot name="header" :status="status" :progress="progress">
					<l-loading type="spinner" :animated="status == 'loading'" style="padding-right: 5px;"></l-loading>
					<text class="l-pull-refresh__header-text">{{loadingText}}</text>
				</slot>
			</view>
			<slot></slot>
		</view>
	</view>
</template>
<script lang="ts">
	// @ts-nocheck
	import { defineComponent, ref, computed, watch, onMounted, watchEffect } from '@/uni_modules/lime-shared/vue';
	import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
	import pullRefreshProps from './props';
	
	export default defineComponent({
		props: pullRefreshProps,
		emits: ["refresh", "update:disabled", "update:modelValue", "input"],
		setup(props, { expose, emit }) {
			const status = ref<RefreshStatus>("initial");
			const translateY = ref(0);
			const isDragging = ref(false);
			
			const maxDragPx = computed(() => unitConvert(props.maxDrag))
			const headerHeightPx = computed(() => unitConvert(props.headerHeight))
			const thresholdPx = computed(() => unitConvert(props.threshold))
			const innerValue = computed(()=> {
				// #ifdef VUE2
				return props.value
				// #endif
				// #ifndef VUE2
				return props.modelValue
				// #endif
			})
			
			let toInitialTimer = -1
			let toRecoveringTimer = -1
			
			const loadingText = computed(() : string => {
				if (status.value == 'pulling') {
					return props.loadingTexts[0]
				}
				else if (status.value == 'ready') {
					return props.loadingTexts[1]
				}
				else if (status.value == 'loading') {
					return props.loadingTexts[2]
				}
				return props.loadingTexts?.[3] ?? '下拉刷新'
			})
			
			const progress = computed(() => {
				return Math.min(translateY.value / thresholdPx.value, 1);
			});
			
			const headerStyle = computed(() => {
				const style = {}
				style['height'] = `${headerHeightPx.value}px`
				return style
			})
			const pullDownRefreshStyle = computed(() => {
				const style = {}
				style['transform'] = `translateY(${translateY.value}px)`
				style['transitionDuration'] = (isDragging.value ? 0 : props.transitionDuration) + "ms"
				style['pointer-events'] = status.value == 'loading' ? `none` : `auto`
				return style
			})
			
			let startX = 0;
			let startY = 0;
			let isMovable = false;
			let scrollLockDirection: 'vertical' | 'horizontal' | null = null;
			
			
			
			const dampenScroll = (deltaY : number) => {
				const max = maxDragPx.value
				return deltaY < max
					? deltaY
					: max + (deltaY - max) * props.damping
			}
			
			const toLoading = () => {
				clearTimeout(toRecoveringTimer)
				clearTimeout(toInitialTimer)
			
				status.value = "loading";
				translateY.value = headerHeightPx.value;
			};
			
			const toRecovering = () => {
				status.value = "rebounding";
				translateY.value = 0;
			
				toInitialTimer = setTimeout(() => {
					status.value = "initial";
				}, props.transitionDuration)
			};
			
			const toDone = () => {
				status.value = "done";
			
				toInitialTimer = setTimeout(() => {
					toRecovering();
				}, props.doneDuration)
			};
			
			const onTouchStart = (e : UniTouchEvent) => {
				if (props.disabled || !innerValue.value || status.value != "initial") return;
				startX = e.touches[0].clientX;
				startY = e.touches[0].clientY;
				isMovable = true;
			}
			const onTouchMove = (e : UniTouchEvent) => {
				if (!isMovable || scrollLockDirection == "horizontal") return;
				const deltaX = e.touches[0].clientX - startX;
				const deltaY = e.touches[0].clientY - startY;
			
				if (scrollLockDirection == null) {
					scrollLockDirection = Math.abs(deltaY) >= Math.abs(deltaX) && deltaY > 0 ? "vertical" : "horizontal";
				}
				if (scrollLockDirection == "vertical") {
					const offsetY = Math.max(deltaY, 0) / 2;
					status.value = offsetY >= thresholdPx.value ? "ready" : "pulling";
					translateY.value = dampenScroll(offsetY);
					isDragging.value = true;
					e.preventDefault()
					e.stopPropagation()
				}
			}
			const onTouchEnd = (e : UniTouchEvent) => {
				isMovable = false;
				scrollLockDirection = null;
				isDragging.value = false;
				if (status.value == 'ready') {
					toLoading()
					emit('refresh')
				} else if (status.value == 'pulling') {
					toRecovering()
				}
			}
			
			
			const enable = (can : boolean) => {
				emit("update:modelValue", can); 
				// #ifdef VUE2
				emit("input", can); 
				// #endif
			};
			
			watch(() : boolean => props.loading, (val : boolean) => {
				val ? toLoading() : toDone()
			})
			
			
			onMounted(() => {
				if (!props.loading) return
				toLoading();
			});
			
			// #ifdef VUE3
			expose({
				enable
			})
			// #endif
			
			return {
				status,
				loadingText,
				progress,
				headerStyle,
				pullDownRefreshStyle,
				onTouchStart,
				onTouchMove,
				onTouchEnd,
				// #ifdef VUE2
				enable
				// #endif
			}
		}
	})
</script>
<style lang="scss">
	@import './index';
</style>
